using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.AddressableAssets.Build;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEngine;

/// <summary>
/// Addressable 管理工具的辅助工具类
/// 提供一些基础的 API 或者作为代码使用参考
/// </summary>
public static class AAManagementUtils
{
    // 获取对应名称 group 
    public static AddressableAssetGroup GetAAGroup(string groupName)
    {
        var aa_setting = GetSettings();

        var group = aa_setting.FindGroup(groupName);
        if (group == null)
        {
            group = aa_setting.CreateGroup(groupName,
                false,
                false,
                false,
                null,
                typeof(ContentUpdateGroupSchema),
                typeof(BundledAssetGroupSchema));
        }

        return group;
    }

    // 获取指定路径的工程相对路径
    public static string GetAssetPath(string fullPath)
    {
        // 若是 Assets/ 开头的路径视为工程路径
        if (!fullPath.Contains("/Assets"))
        {
            return fullPath;
        }

        var tmp = new Uri(fullPath).Segments;
        var relative = new StringBuilder();
        bool isStart = false;
        for (int j = 0; j < tmp.Length; j++)
        {
            if (tmp[j].Equals("Assets/"))
                isStart = true;
            if (isStart)
                relative.Append(tmp[j]);
        }

        return relative.ToString();
    }


    /// <summary>
    /// Asset 路径 转换到 全局路径
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string RelaToFullPath(this string path)
    {
        return new Regex("^Assets").Replace(path, Application.dataPath);
    }

    /// <summary>
    /// 全局路径 转换到 Asset 路径
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string FullPathToRela(this string path)
    {
        return path.Replace(Application.dataPath, "Assets");
    }

    /// <summary>
    /// 创建文件对应父级文件夹
    /// </summary>
    /// <param name="file"></param>
    /// <param name="parentPath"></param>
    /// <returns></returns>
    public static string CreateParentDirectory(string file, string parentPath)
    {
        string[] lastFolds = file.Split('\\');
        StringBuilder sb = new StringBuilder(parentPath);
        for (int j = 1; j < lastFolds.Length - 1; j++)
        {
            sb.Append(lastFolds[j]);
            sb.Append("/");
        }

        var destFold = sb.ToString();
        if (!Directory.Exists(destFold))
            Directory.CreateDirectory(destFold);

        return destFold;
    }

    /// <summary>
    /// 设置 group 的 Assets
    /// </summary>
    /// <param name="files"></param>
    /// <param name="group"></param>
    public static void AssignAssets(string[] files, AddressableAssetGroup group, string label = "",
        string extraName = "")
    {
        for (int j = 0; j < files.Length; j++)
        {
            var file = files[j];
            var tp = GetAssetPath(file);
            // var obj = AssetDatabase.LoadAssetAtPath<Object>(tp);
            var guid = AssetDatabase.AssetPathToGUID(tp);
            if (string.IsNullOrEmpty(guid))
            {
                Debug.LogWarning("");
                continue;
            }

            var entry = GetSettings().CreateOrMoveEntry(guid, group);
            var addrName = Path.GetFileNameWithoutExtension(file);
            if (!string.IsNullOrEmpty(extraName))
                addrName += $"_{extraName}";

            entry.SetAddress(addrName, false);
            // set label
            if (!string.IsNullOrEmpty(label))
            {
                TryLabel(label);
                entry.SetLabel(label, true);
            }
        }
    }

    /// <summary>
    /// 尝试设置 label 
    /// </summary>
    /// <param name="label"></param>
    /// <param name="autoAdd"></param>
    public static void TryLabel(string label, bool autoAdd = true)
    {
        if (string.IsNullOrEmpty(label))
        {
            return;
        }

        var setting = GetSettings();
        if (!setting.GetLabels().Contains(label) && autoAdd)
        {
            setting.AddLabel(label);
        }
    }

    public static AddressableAssetSettings GetSettings()
    {
        var setting = AssetDatabase.LoadAssetAtPath<AddressableAssetSettings>(
            "Assets/AddressableAssetsData/AddressableAssetSettings.asset");

        if (setting == null)
        {
            Debug.LogError("【AddressableGroupManager】addressable setting can't find.");
        }

        return setting;
    }

    public static BundledAssetGroupSchema GetGroupSchema(string groupName)
    {
        return AssetDatabase.LoadAssetAtPath<BundledAssetGroupSchema>(
            $"Assets/AddressableAssetsData/AssetGroups/Schemas/{groupName}_BundledAssetGroupSchema.asset");
    }

    public static void SwitchProfilerRemotePath(string profilerName)
    {
        var aa_setting = GetSettings();
        var profileId = aa_setting.profileSettings.GetProfileId(profilerName);
        if (!string.IsNullOrEmpty(profileId))
        {
            aa_setting.activeProfileId = profileId;
        }
        else
        {
            Debug.LogError("[AddressableGroupsManager] profilerName can't find target: " + profilerName);
        }
    }

    public static AddressablesPlayerBuildResult CustomBuilding(out AddressablesPlayerBuildResult result)
    {
        var setting = GetSettings();
        setting.ActivePlayerDataBuilderIndex = 5;
        AddressableAssetSettings.BuildPlayerContent(out result);
        return result;
    }
    
    
    /// <summary>
    /// 通过 guid 找到依赖的 group
    /// </summary>
    /// <param name="setting"></param>
    /// <param name="guid"></param>
    /// <returns></returns>
    public static AddressableAssetGroup FindDepGroupByGuid(this AddressableAssetSettings setting,  string guid)
    {
        var groups = setting.groups;
        foreach (var group in setting.groups)
        {
            if (group.GetAssetEntry(guid) != null)
                return group;
        }

        return null;
    }
}